package com.quad.innovators.salesease.service.impl.task;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.quad.innovators.salesease.common.result.PageResultBean;
import com.quad.innovators.salesease.common.utils.SystemCodeUtils;
import com.quad.innovators.salesease.converter.TaskDistributionConverter;
import com.quad.innovators.salesease.enums.ResultCode;
import com.quad.innovators.salesease.enums.SystemCodeEnum;
import com.quad.innovators.salesease.enums.TagTypeEnum;
import com.quad.innovators.salesease.enums.TaskAddressTypeEnum;
import com.quad.innovators.salesease.enums.TaskStatusEnums;
import com.quad.innovators.salesease.exception.BusinessException;
import com.quad.innovators.salesease.mapper.base.ShopMapper;
import com.quad.innovators.salesease.mapper.base.WarehouseMapper;
import com.quad.innovators.salesease.mapper.tag.TagMapper;
import com.quad.innovators.salesease.mapper.tag.TagTaskMapper;
import com.quad.innovators.salesease.mapper.task.TaskAddressMapper;
import com.quad.innovators.salesease.mapper.task.TaskDistributionMapper;
import com.quad.innovators.salesease.model.entity.base.Shop;
import com.quad.innovators.salesease.model.entity.base.Warehouse;
import com.quad.innovators.salesease.model.entity.tag.Tag;
import com.quad.innovators.salesease.model.entity.tag.TagTask;
import com.quad.innovators.salesease.model.entity.task.TaskAddress;
import com.quad.innovators.salesease.model.entity.task.TaskDistribution;
import com.quad.innovators.salesease.model.form.task.TaskDistributionForm;
import com.quad.innovators.salesease.model.query.task.TaskDistributionQuery;
import com.quad.innovators.salesease.model.vo.task.TagTaskVO;
import com.quad.innovators.salesease.model.vo.task.TaskAddressVO;
import com.quad.innovators.salesease.model.vo.task.TaskDistributionVO;
import com.quad.innovators.salesease.service.task.TagTaskService;
import com.quad.innovators.salesease.service.task.TaskAddressService;
import com.quad.innovators.salesease.service.task.TaskDistributionService;

import lombok.RequiredArgsConstructor;

import org.apache.commons.compress.utils.Lists;
import org.apache.commons.compress.utils.Sets;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author cheng
 */
@Service
@RequiredArgsConstructor
public class TaskDistributionServiceImpl extends ServiceImpl<TaskDistributionMapper, TaskDistribution> implements TaskDistributionService {

    private final TaskDistributionConverter taskDistributionConverter;

    private final TaskAddressMapper taskAddressMapper;

    private final TagTaskMapper tagTaskMapper;

    private final TaskAddressService taskAddressService;

    private final TagTaskService tagTaskService;


    @Override
    public PageResultBean<TaskDistributionVO> listPaged(TaskDistributionQuery queryParams) {
        Page<TaskDistributionVO> page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize());
        Set<String> taskCodeSet = Sets.newHashSet();
        // 根据执行位置筛选任务
        if (ObjectUtil.isNotEmpty(queryParams.getAddressCode()) && ObjectUtil.isNotEmpty(queryParams.getAddressType())) {
            TaskAddressTypeEnum taskAddressTypeEnum = TaskAddressTypeEnum.useCodeGetEnum(queryParams.getAddressType());
            List<TaskAddress> taskAddressList = taskAddressMapper.selectList(
                    new LambdaQueryWrapper<TaskAddress>()
                            .eq(TaskAddressTypeEnum.WAREHOUSE.equals(taskAddressTypeEnum), TaskAddress::getWarehouseCode, queryParams.getAddressCode())
                            .or()
                            .eq(TaskAddressTypeEnum.SHOP.equals(taskAddressTypeEnum), TaskAddress::getShopCode, queryParams.getAddressCode())
            );
            if (CollectionUtils.isEmpty(taskAddressList)) {
                return taskDistributionConverter.toPageVo(page);
            }
            taskCodeSet.addAll(taskAddressList.stream().map(TaskAddress::getTaskCode).collect(Collectors.toSet()));
        }

        // 根据标签筛选任务
        if (ObjectUtils.isNotEmpty(queryParams.getTagCode())) {
            List<TagTask> tagTaskList = tagTaskMapper.selectList(new LambdaQueryWrapper<TagTask>().eq(TagTask::getTagCode, queryParams.getTagCode()));
            if (CollectionUtils.isEmpty(tagTaskList)) {
                return taskDistributionConverter.toPageVo(page);
            }
            Set<String> finalTaskCodeSet = taskCodeSet;
            taskCodeSet = tagTaskList.stream().map(TagTask::getTaskDistributionCode).filter(finalTaskCodeSet::contains).collect(Collectors.toSet());
        }
        Page<TaskDistributionVO> taskDistributionVOPage = this.baseMapper.listPaged(page, queryParams, taskCodeSet);
        List<TaskDistributionVO> taskDistributionVOList = taskDistributionVOPage.getRecords();
        if (CollectionUtils.isEmpty(taskDistributionVOList)) {
            return taskDistributionConverter.toPageVo(taskDistributionVOPage);
        }
        List<String> taskCodeList = taskDistributionVOList.stream().map(TaskDistributionVO::getCode).toList();

        // 设置执行位置
        List<TaskAddressVO> addressListByTaskCodeList = taskAddressService.getAddressListByTaskCodeList(taskCodeList, queryParams.getH5NotShopFinishTaskAddress());
        Map<String, List<TaskAddressVO>> addressListGroupByTaskCode = addressListByTaskCodeList.stream().collect(Collectors.groupingBy(TaskAddressVO::getTaskCode));

        // 设置标签
        List<TagTaskVO> tagTaskVOList = tagTaskService.getTagNameByTaskCodeList(taskCodeList);
        Map<String, List<TagTaskVO>> tagListGroupByTaskCode = tagTaskVOList.stream().collect(Collectors.groupingBy(TagTaskVO::getTaskDistributionCode));

        taskDistributionVOPage.getRecords().forEach(model -> {
            model.setAddress(addressListGroupByTaskCode.getOrDefault(model.getCode(), Lists.newArrayList()).stream().map(TaskAddressVO::getAddressName).toList());
            model.setTagCodeList(tagListGroupByTaskCode.getOrDefault(model.getCode(), Lists.newArrayList()).stream().map(TagTaskVO::getTagName).toList());
        });
        return taskDistributionConverter.toPageVo(taskDistributionVOPage);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(TaskDistributionForm form) {
        if (CollectionUtils.isEmpty(form.getTaskAddressFormList())) {
            throw BusinessException.resultCode(ResultCode.COLLECTION_NOT_EMPTY);
        }
        TaskDistribution taskDistribution = taskDistributionConverter.toEntity(form);
        taskDistribution.setCode(SystemCodeUtils.getCode(SystemCodeEnum.TASK));
        LocalDate now = LocalDate.now();
        if (now.isBefore(taskDistribution.getStartTime())) {
            taskDistribution.setStatus(TaskStatusEnums.NOT_START.getValue());
        } else {
            taskDistribution.setStatus(TaskStatusEnums.UNFINISHED.getValue());
        }

        if (now.isAfter(taskDistribution.getDeadline())) {
            throw BusinessException.resultCode(ResultCode.TASK_OUT_TIME);
        }

        form.getTaskAddressFormList().forEach(model -> {
            model.setTaskCode(taskDistribution.getCode());
            model.setTaskAddressStatus(taskDistribution.getStatus());
        });

        if (CollectionUtils.isNotEmpty(form.getTagCodeList())) {
            tagTaskService.addTagTaskList(form.getTagCodeList(), taskDistribution.getCode());
        }
        return taskAddressService.addList(form.getTaskAddressFormList(), form.getAddressType()) &&
                this.baseMapper.insert(taskDistribution) > 0;
    }

    @Override
    public boolean update(String code, TaskDistributionForm form) {
        // if (org.springframework.util.CollectionUtils.isEmpty(form.getTaskAddressFormList())) {
        //     throw BusinessException.resultCode(ResultCode.COLLECTION_NOT_EMPTY);
        // }
        TaskDistribution distribution =
                this.baseMapper.selectOne(
                        new LambdaQueryWrapper<TaskDistribution>().eq(TaskDistribution::getCode, code));
        if (distribution == null) {
            throw BusinessException.resultCode(ResultCode.NOT_FOUND);
        }
        // 暂时只支持修改备注
        distribution.setSpecificTask(form.getSpecificTask());

        // if (CollectionUtils.isNotEmpty(form.getTagCodeList())){
        //     tagTaskService.addTagTaskList(form.getTagCodeList(), distribution.getCode());
        // }
        // return taskAddressMapper.delete(new LambdaQueryWrapper<TaskAddress>()
        //         .eq(TaskAddress::getTaskCode, taskDistribution.getCode())) > 0 &&
        //         taskAddressService.addList(form.getTaskAddressFormList(), form.getAddressType()) &&
        return baseMapper.updateById(distribution) > 0;
    }

    @Override
    public TaskDistributionForm getFormData(String code) {
        TaskDistribution distribution =
                this.baseMapper.selectOne(
                        new LambdaQueryWrapper<TaskDistribution>().eq(TaskDistribution::getCode, code));
        if (distribution == null) {
            throw BusinessException.resultCode(ResultCode.NOT_FOUND);
        }
        TaskDistributionForm taskDistributionForm = taskDistributionConverter.toForm(distribution);
        taskDistributionForm.setTaskAddressFormList(taskAddressService.getTaskAddressVOByTaskCode(code, distribution.getAddressType()));
        List<TagTask> tagTaskList = tagTaskMapper.selectList(new QueryWrapper<TagTask>().lambda().eq(TagTask::getTaskDistributionCode, code));
        taskDistributionForm.setTagCodeList(tagTaskList.stream().map(TagTask::getTagCode).collect(Collectors.toList()));
        return taskDistributionForm;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateStatus(String code, Integer status, Integer addressType, String addressCode) {
        TaskDistribution formData = this.baseMapper.selectOne(new LambdaQueryWrapper<TaskDistribution>().eq(TaskDistribution::getCode, code));
        // 总任务修改
        if (formData == null) {
            throw BusinessException.resultCode(ResultCode.NOT_FOUND);
        }
        formData.setStatus(status);
        // 任务单门店修改
        if (ObjectUtils.isNotNull(addressType)) {
            TaskAddressTypeEnum taskAddressTypeEnum = TaskAddressTypeEnum.useCodeGetEnum(addressType);
            TaskAddress taskAddress = taskAddressMapper.selectOne(new LambdaQueryWrapper<TaskAddress>().eq(TaskAddress::getTaskCode, code)
                    .eq(TaskAddressTypeEnum.WAREHOUSE.equals(taskAddressTypeEnum), TaskAddress::getWarehouseCode, addressCode)
                    .eq(TaskAddressTypeEnum.SHOP.equals(taskAddressTypeEnum), TaskAddress::getShopCode, addressCode));
            if (taskAddress == null) {
                throw BusinessException.resultCode(ResultCode.NOT_FOUND);
            }
            taskAddress.setTaskAddressStatus(status);
            boolean updateAddressStatus = taskAddressMapper.updateById(taskAddress) > 0;
            List<TaskAddress> taskAddressList = taskAddressMapper.selectList(new QueryWrapper<TaskAddress>().lambda().eq(TaskAddress::getTaskCode, code));
            List<TaskAddress> addressList = taskAddressList.stream().filter(model -> !TaskStatusEnums.COMPLETED.getValue().equals(model.getTaskAddressStatus())).toList();
            int updated = 1;
            if (CollectionUtils.isEmpty(addressList)) {
                updated = this.baseMapper.updateById(formData);
            }
            return updateAddressStatus && updated > 0;
        }
        return this.baseMapper.updateById(formData) > 0
                && taskAddressMapper.update(new UpdateWrapper<TaskAddress>().lambda()
                .eq(TaskAddress::getTaskCode, code)
                .set(TaskAddress::getTaskAddressStatus, status)) > 0;
    }

}
